/*
 * File:   MFQS.cpp
 * Author: Adrienne
 *
 * Created on November 7, 2010, 7:49 PM
 */

#include "MFQS.h"
#include "Process.h"

//generic constructor

MFQS::MFQS(int queues, int aTime, int quant, Process * pArray) {
    cout << "MFQS Constructor"<< endl;
    numQueues = queues;
    ageTime = aTime;
    quantum = quant;
    processes = pArray;
    curProcess = pArray; // i dont think this is right... what if the
    // first process arrives at t == 15?
    clock;
    endTime;
    totalWait = 0;
    totalTurnaround = 0;
    queueList[queues - 1];
    holdingQueue; //used to hold
    


    //currentRemaining = 0; // what is this?

    //have to instatiate queues, or we get a seg fault...
    for(int i = 0; i < queues-1; i++){
        (queueList + i) -> NULL ;
    }
    cout << "MFQS Constructor End"<< endl;
}

void MFQS::run(){};

/*
 * needs to be given the initial process array
 */
void MFQS::scheduleProcesses() {
    cout << "MFQS Schduling Processes"<< endl;
    int processCount;
    bool queuesEmpty = false;
    int queue;
    int currentQuantum;
    //create queues
    //if(numQueues == 2){
    //    queueList[0] = queue<Process>;
   //     cout<< "queue successfully created" << endl;
   // }else if(numQueues == 3){
       // queue<Process> queue2;
       // queue<Process> queue3;
   // }else if(numQueues == 4){
       // queue<Process> queue2;
        //queue<Process> queue3;
       // queue<Process> queue4;
   // }else if(numQueues == 5){
       // queue<Process> queue2;
       // queue<Process> queue3;
       // queue<Process> queue4;
       // queue<Process> queue5;
   // }


    //while there are more processes...
    while (curProcess != NULL && !queuesEmpty) {
        //reset values
        startTime = clock.getTime(); //this process's start time is the current clock time
        // ** use curProcess.getRemaining() for remaining
        // ** use curProcess--; to decrease remaining time by 1.

        //currentRemaining = curProcess.getBurst();
        queue = 0;
        currentQuantum = quantum;
     
        //check to make sure next process to be run is "present"
        //if there is no next process, run the other queues

        if ((curProcess != NULL) && (curProcess->getArrive() <= startTime)) {
            cout<< "Process ready to run, Queue 1" << endl;
            //run the process
            runProcess(curProcess, queue, currentQuantum, curProcess->getRemaining());

            /* using the class var */

            processCount++; //increment to grab next process at end of loop

        }
            //start running other queues
        else {
            //determine the next queue which has processes to run
            while ((queue < numQueues - 1) && (&(queueList[queue])!= NULL)) {
                queue++;
            }

            //if the queues are empty, spin clock until next process arrives
            if ((queue == numQueues - 1) || (queue == 0)){
                //if there is another process, but it hasn't arrived yet...
                if (curProcess != NULL) {
                    while (curProcess->getArrive() > clock.getTime()) { //spin CPU
                        cout << "No process running " << clock.getTime() << endl;
                        ++clock;
                    }
                }
                    //otherwise, all processes have been completed
                else {
                    queuesEmpty = true;
                }

            }
                //FCFS case
            else if (queue == numQueues - 2) {
                //run until process completes
                *curProcess = queueList[queue].front();
                queueList[queue].pop();

                // error here
                runProcess(curProcess, queue, curProcess->getRemaining(), curProcess->getRemaining());
            }
                //other cases, run next available process
            else {

                //find quantum of this queue
                for (int j = 0; j < queue; j++){
                    currentQuantum = currentQuantum * 2;
                }

                //set next process
                *curProcess = queueList[queue].front();
                queueList[queue].pop();

                //run the process
                runProcess(curProcess, queue, currentQuantum, curProcess->getRemaining());
            }

        }
        cout << "Issue aging up" << (&(queueList[numQueues - 1]) != NULL)<<endl;
        //finally, age up necessary processes
        while (&(queueList[numQueues - 1]) != NULL) {
            while (!queueList[numQueues - 1].empty()) { //while the FCFS queue has more processes
                *curProcess = queueList[numQueues - 1].front();
                queueList[numQueues - 1].pop(); //pop the first process
                if (curProcess->getLastExe() > ageTime) {
                    queueList[numQueues - 2].push(*curProcess); //move up one queue if starving
                } else {
                    queueList[numQueues - 1].push(*curProcess); //push to the back of FCFS if !starving
                }
            }
        }

        cout << "Issue getting new pointer" << endl;
        //get pointer to next process
        curProcess = processes + processCount;
    }
}

//

void MFQS::runProcess(Process * currentProcess, int q, int quant, int currentRemaining) {
    //print which queue is running
    cout << "************ Queue " << q << ", Quantum " << quant << " ************" << endl;

    //calculate current wait time
    if (q == 0) {
        totalWait = clock.getTime() - currentProcess->getArrive();
    } else {
        totalWait = totalWait + clock.getTime() + currentProcess->getLastExe();
    }

    endTime = startTime + quant;
    while (clock.getTime() <= endTime && currentRemaining > 0) {
        cout << currentProcess->getID() << clock.getTime() << endl;
        ++clock;
        --(*currentProcess); //decrement remaining burst for current process
    }

    //if process isn't complete, update remaining, add to next queue
    if (currentRemaining > 0) {
        currentProcess->setLastExe(endTime);
        queueList[q + 1].push(*currentProcess);
    }        //if process has completed, calculate turnaround time, delete process
    else {
        totalTurnaround = totalTurnaround + (clock.getTime() - currentProcess->getArrive());
        //delete_currentProcess;
    }
}
